package com.jinzhi.jinzhidata.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.jinzhi.jinzhidata.util.CookieUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @description
 * @date 2019-12-27 12:45
 **/
public class JwtUtil {

    /**
     * 过期时间
     * todo 线上版本改为 7 * 24 * 60 * 60 * 1000
     */
    public static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;
//    public static final long EXPIRE_TIME = 60 * 1000;

    /**
     * Token私钥
     */
    public static final String TOKEN_SECRET = "84347e88e373489f95d529bba3dd03a0";

    /**
     * 生成token
     */
    public static String sign(String phoneNum, String verificationCode, long opTime) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            Map<String, Object> header = new HashMap<String, Object>(3);
            header.put("typ", "JWT");
            header.put("alg", "HS256");
            return JWT.create()
                    .withHeader(header)
                    .withClaim("phoneNum", phoneNum)
                    .withClaim("verificationCode", verificationCode)
                    .withClaim("opTime", opTime)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String sign(String userId, String loginType) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            Map<String, Object> header = new HashMap<String, Object>(1);
            header.put("typ", "JWT");
            header.put("alg", "HS256");
            return JWT.create()
                    .withHeader(header)
                    .withClaim("userId", userId)
                    .withClaim("loginType", loginType)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 校验token
     */
    public static boolean verify(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            return true;
        } catch (UnsupportedEncodingException | TokenExpiredException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 解密JWT
     */
    public static String decodeUserId(String token, String name) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            return decodedJWT.getClaim(name).asString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Map<String, String> decodeVerificationCode(String token) {
        Map<String, String> map = new HashMap<>();
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            map.put("verificationCode", decodedJWT.getClaim("verificationCode").asString());
            map.put("opTime", decodedJWT.getClaim("opTime").asLong().toString());
            map.put("phoneNum", decodedJWT.getClaim("phoneNum").asString());
            return map;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return map;
        }
    }

    /**
     * 校验已有token
     */
    public static String verifyAccessToken(String token) {
        if (token == null) {
            return null;
        }
        boolean result = verify(token);
        if (result) {
            String userId = decodeUserId(token, "userId");
            if (userId == null) {
                return null;
            } else {
                return userId;
            }
        } else {
            return null;
        }
    }

    /**
     * 校验已有token
     */
    public static String verifyAccessToken(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String token = httpServletRequest.getHeader("accessToken");
        if (token == null) {
            token = CookieUtil.getCookieValue(httpServletRequest, "accessToken");
            if (token == null) {
                return null;
            }
        }
        boolean result = verify(token);
        if (result) {
            String userId = decodeUserId(token, "userId");
            if (userId == null) {
                return null;
            } else {
                return userId;
            }
        } else {
            CookieUtil.deleteCookie(httpServletRequest, httpServletResponse, "accessToken");
            return null;
        }
    }

    public static String verifyLoginType(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String token = httpServletRequest.getHeader("accessToken");
        if (token == null) {
            token = CookieUtil.getCookieValue(httpServletRequest, "accessToken");
            if (null == token) {
                return null;
            }
        }
        boolean result = verify(token);
        if (result) {
            String loginType = decodeUserId(token, "loginType");
            if (null == loginType) {
                return null;
            } else {
                return loginType;
            }
        } else {
            CookieUtil.deleteCookie(httpServletRequest, httpServletResponse, "accessToken");
            return null;
        }
    }

    public static Map<String, String> verifyCodeToken(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String token = httpServletRequest.getHeader("verificationCode");
        if (null == token) {
            token = CookieUtil.getCookieValue(httpServletRequest, "verificationCode");
            if (null == token) {
                return null;
            }
        }
        boolean result = verify(token);
        if (result) {
            Map<String, String> map = decodeVerificationCode(token);
            if (map.isEmpty()) {
                return null;
            } else {
                return map;
            }
        } else {
            CookieUtil.deleteCookie(httpServletRequest, httpServletResponse, "verificationCode");
            return null;
        }
    }
}

